﻿using System;
using System.Collections.Generic;
using Chess.Screens;
using Chess.ScreensManager;
using Microsoft.Xna.Framework;

namespace Chess
{
    enum FigureTypes
    {
        Pawn,
        Rook,
        Knight,
        Bishop,
        Queen,
        King
    }

    enum FiguresColor
    {
        White,
        Black
    }

    /// <summary>
    /// Chessboard presentation for game logic.
    /// It is 2D array. The X coordinate is up,
    /// and Y coordinate is right.
    /// </summary>
    class ChessboardState
    {
        #region Constants, structs and fields

        static int figuresNumber = 32;
        static public int FiguresNumber
        {
            get { return figuresNumber; }
        }

        // Struct that represents figure type, vector position and figure color
        struct FigurePositionColor
        {
            FigureTypes figure;
            Vector2 position;
            FiguresColor color;
            public FigurePositionColor(FigureTypes figure, Vector2 position,
                FiguresColor color)
            {
                this.figure = figure;
                this.position = position;
                this.color = color;
            }
            public FigureTypes Figure
            {
                get { return figure; }
            }
            public Vector2 Position
            {
                get { return position; }
            }
            public FiguresColor Color
            {
                get { return color; }
            }
        }

        SortedList<int, FigurePositionColor?> numberFigurePositionColor =
            new SortedList<int, FigurePositionColor?>();
        SortedList<int, FigurePositionColor?> numberFigurePositionColorCopy =
            new SortedList<int, FigurePositionColor?>();
        FiguresColor currentMoveColor = FiguresColor.White;

        // Global castling rules
        private bool whiteKingsideCastling = true;
        private bool whiteQueensideCastling = true;
        private bool blackKingsideCastling = true;
        private bool blackQueensideCastling = true;

        // save the position of pawn that must be transformed
        private Vector2 pawnToPositionForTransformation;

        // Show choose figure box in gameplay screen
        public event EventHandler<EventArgs> ShowChooseFigureBox;

        // Change model for transformed pawn
        public event EventHandler<FigureNumberEventArgs> FigureChanged;

        // en passant postition
        Vector2? enPassant = null;

        #endregion
        
        /// <summary>
        /// Constructor.
        /// </summary>
        public ChessboardState()
        {
            #region Placing figures on board
            for (int i = 0; i < 2; i++)
            {
                FiguresColor figureColor = (i == 0) ? FiguresColor.White : FiguresColor.Black;

                numberFigurePositionColor.Add(16 * i, new FigurePositionColor(
                    FigureTypes.Rook, new Vector2(7 * i, 0), figureColor));
                numberFigurePositionColor.Add(16 * i + 1, new FigurePositionColor(
                    FigureTypes.Rook, new Vector2(7 * i, 7), figureColor));

                numberFigurePositionColor.Add(16 * i + 2, new FigurePositionColor(
                    FigureTypes.Knight, new Vector2(7 * i, 1), figureColor));
                numberFigurePositionColor.Add(16 * i + 3, new FigurePositionColor(
                    FigureTypes.Knight, new Vector2(7 * i, 6), figureColor));

                numberFigurePositionColor.Add(16 * i + 4, new FigurePositionColor(
                    FigureTypes.Bishop, new Vector2(7 * i, 2), figureColor));
                numberFigurePositionColor.Add(16 * i + 5, new FigurePositionColor(
                    FigureTypes.Bishop, new Vector2(7 * i, 5), figureColor));

                numberFigurePositionColor.Add(16 * i + 6, new FigurePositionColor(
                    FigureTypes.Queen, new Vector2(7 * i, 3), figureColor));

                numberFigurePositionColor.Add(16 * i + 7, new FigurePositionColor(
                    FigureTypes.King, new Vector2(7 * i, 4), figureColor));

                for (int j = 0; j < 8; j++)
                {
                    numberFigurePositionColor.Add(16 * i + 8 + j, new FigurePositionColor(
                        FigureTypes.Pawn, new Vector2(5 * i + 1, j), figureColor));
                }
            }
            #endregion
        }
        
        #region Figures move

        /// <summary>
        /// Change figure position in this class.
        /// </summary>
        /// <param name="figureNumber">Number of figure.</param>
        /// <param name="to">Destination of figure.</param>
        /// <returns>True, if move was performed.</returns>
        public bool Move(int figureNumber, Vector2 from, Vector2 to)
        {
            if (to == from)
                return false;

            if ((to.X < 0) || (to.Y < 0) || (to.X > 7) || (to.Y > 7))
                return false;

            FigurePositionColor? movingFigure;
            if (!numberFigurePositionColor.TryGetValue(figureNumber, out movingFigure))
                return false;

            FigurePositionColor? attackedFigure = null;
            int? attackedFigureNumber = FindFigureNumber(to, false);
            if (attackedFigureNumber.HasValue)
                if (!numberFigurePositionColor.TryGetValue(attackedFigureNumber.Value, out attackedFigure))
                    return false;

            if (movingFigure.Value.Color != currentMoveColor)
                return false;

            if (attackedFigureNumber.HasValue)
                if (movingFigure.Value.Color == attackedFigure.Value.Color)
                    return false;

            // Create copy of chessboard to test the future possible position
            numberFigurePositionColorCopy.Clear();
            for (int i = 0; i < numberFigurePositionColor.Count; i++)
                numberFigurePositionColorCopy.Add(numberFigurePositionColor.Keys[i],
                    numberFigurePositionColor.Values[i]);

            if (movingFigure.Value.Figure == FigureTypes.Bishop)
            {
                #region Bishop rules
                if ((to.X - from.X == to.Y - from.Y) && (to.X > from.X)) // right up
                {
                    for (int i = 0; i < to.X - from.X - 1; i++)
                        if (FindFigureNumber(from + (i + 1) * Vector2.One, false).HasValue)
                            return false;
                }
                else if ((to.X - from.X == to.Y - from.Y) && (to.X < from.X)) // left down
                {
                    for (int i = 0; i < from.X - to.X - 1; i++)
                        if (FindFigureNumber(from - (i + 1) * Vector2.One, false).HasValue)
                            return false;
                }
                else if ((to.X - from.X == from.Y - to.Y) && (to.X > from.X)) //right down
                {
                    for (int i = 0; i < to.X - from.X - 1; i++)
                        if (FindFigureNumber(from + (i + 1) * new Vector2(1.0f, -1.0f), false).HasValue)
                            return false;
                }
                else if ((to.X - from.X == from.Y - to.Y) && (to.X < from.X)) //left up
                {
                    for (int i = 0; i < from.X - to.X - 1; i++)
                        if (FindFigureNumber(from - (i + 1) * new Vector2(1.0f, -1.0f), false).HasValue)
                            return false;
                }
                else
                    return false;
                #endregion
            }
            else if (movingFigure.Value.Figure == FigureTypes.Rook)
            {
                #region Rook rules
                if ((to.Y == from.Y) && (to.X > from.X)) // right
                {
                    for (int i = 0; i < to.X - from.X - 1; i++)
                        if (FindFigureNumber(from + (i + 1) * Vector2.UnitX, false).HasValue)
                            return false;
                }
                else if ((to.Y == from.Y) && (to.X < from.X)) // left
                {
                    for (int i = 0; i < from.X - to.X - 1; i++)
                        if (FindFigureNumber(from - (i + 1) * Vector2.UnitX, false).HasValue)
                            return false;
                }
                else if ((to.X == from.X) && (to.Y > from.Y)) // up
                {
                    for (int i = 0; i < to.Y - from.Y - 1; i++)
                        if (FindFigureNumber(from + (i + 1) * Vector2.UnitY, false).HasValue)
                            return false;
                }
                else if ((to.X == from.X) && (to.Y < from.Y)) // down
                {
                    for (int i = 0; i < from.Y - to.Y - 1; i++)
                        if (FindFigureNumber(from - (i + 1) * Vector2.UnitY, false).HasValue)
                            return false;
                }
                else
                    return false;
                #endregion
            }
            else if (movingFigure.Value.Figure == FigureTypes.Queen)
            {
                #region Queen rules
                if ((to.X - from.X == to.Y - from.Y) && (to.X > from.X)) // right up
                {
                    for (int i = 0; i < to.X - from.X - 1; i++)
                        if (FindFigureNumber(from + (i + 1) * Vector2.One, false).HasValue)
                            return false;
                }
                else if ((to.X - from.X == to.Y - from.Y) && (to.X < from.X)) // left down
                {
                    for (int i = 0; i < from.X - to.X - 1; i++)
                        if (FindFigureNumber(from - (i + 1) * Vector2.One, false).HasValue)
                            return false;
                }
                else if ((to.X - from.X == from.Y - to.Y) && (to.X > from.X)) //right down
                {
                    for (int i = 0; i < to.X - from.X - 1; i++)
                        if (FindFigureNumber(from + (i + 1) * new Vector2(1.0f, -1.0f), false).HasValue)
                            return false;
                }
                else if ((to.X - from.X == from.Y - to.Y) && (to.X < from.X)) //left up
                {
                    for (int i = 0; i < from.X - to.X - 1; i++)
                        if (FindFigureNumber(from - (i + 1) * new Vector2(1.0f, -1.0f), false).HasValue)
                            return false;
                }
                else if ((to.Y == from.Y) && (to.X > from.X)) // right
                {
                    for (int i = 0; i < to.X - from.X - 1; i++)
                        if (FindFigureNumber(from + (i + 1) * Vector2.UnitX, false).HasValue)
                            return false;
                }
                else if ((to.Y == from.Y) && (to.X < from.X)) // left
                {
                    for (int i = 0; i < from.X - to.X - 1; i++)
                        if (FindFigureNumber(from - (i + 1) * Vector2.UnitX, false).HasValue)
                            return false;
                }
                else if ((to.X == from.X) && (to.Y > from.Y)) // up
                {
                    for (int i = 0; i < to.Y - from.Y - 1; i++)
                        if (FindFigureNumber(from + (i + 1) * Vector2.UnitY, false).HasValue)
                            return false;
                }
                else if ((to.X == from.X) && (to.Y < from.Y)) // down
                {
                    for (int i = 0; i < from.Y - to.Y - 1; i++)
                        if (FindFigureNumber(from - (i + 1) * Vector2.UnitY, false).HasValue)
                            return false;
                }
                else
                    return false;
                #endregion
            }
            else if (movingFigure.Value.Figure == FigureTypes.Knight)
            {
                #region Knight rules
                if (to.X - from.X == 2)
                {
                    if (Math.Abs(to.Y - from.Y) != 1)
                        return false;
                }
                else if (to.X - from.X == 1)
                {
                    if (Math.Abs(to.Y - from.Y) != 2)
                        return false;
                }
                else if (to.X - from.X == -1)
                {
                    if (Math.Abs(to.Y - from.Y) != 2)
                        return false;
                }
                else if (to.X - from.X == -2)
                {
                    if (Math.Abs(to.Y - from.Y) != 1)
                        return false;
                }
                else
                    return false;
                #endregion
            }
            else if (movingFigure.Value.Figure == FigureTypes.Pawn)
            {
                #region Pawn rules
                if (movingFigure.Value.Color == FiguresColor.White)
                {
                    if ((to.Y == from.Y) && (to.X - from.X == 1))
                    {
                        if (FindFigureNumber(to, false).HasValue)
                            return false;
                    }
                    else if ((to.Y == from.Y) && (to.X - from.X == 2))
                    {
                        if (from.X != 1)
                            return false;
                        else if (FindFigureNumber(from + Vector2.UnitX, false).HasValue
                            || FindFigureNumber(to, false).HasValue)
                            return false;
                    }
                    else if ((Math.Abs(to.Y - from.Y) == 1) && (to.X - from.X == 1))
                    {
                        if (!FindFigureNumber(to, false).HasValue)
                        {
                            if (!enPassant.HasValue)
                                return false;
                            else if (enPassant.Value != to)
                                return false;
                            // delete enemy pawn
                            numberFigurePositionColorCopy.Remove(
                                FindFigureNumber(enPassant.Value - Vector2.UnitX, true).Value);
                        }
                    }
                    else
                        return false;
                    // check for transformation
                    if (to.X == 7)
                    {
                        if (ShowChooseFigureBox != null)
                            ShowChooseFigureBox(this, new EventArgs());
                        pawnToPositionForTransformation = to;
                    }
                }
                else
                {
                    if ((to.Y == from.Y) && (to.X - from.X == -1))
                    {
                        if (FindFigureNumber(to, false).HasValue)
                            return false;
                    }
                    else if ((to.Y == from.Y) && (to.X - from.X == -2))
                    {
                        if (from.X != 6)
                            return false;
                        else if (FindFigureNumber(from - Vector2.UnitX, false).HasValue
                            || FindFigureNumber(to, false).HasValue)
                            return false;
                    }
                    else if ((Math.Abs(to.Y - from.Y) == 1) && (to.X - from.X == -1))
                    {
                        if (!FindFigureNumber(to, false).HasValue)
                        {
                            if (!enPassant.HasValue)
                                return false;
                            else if (enPassant.Value != to)
                                return false;
                            // delete enemy pawn
                            numberFigurePositionColorCopy.Remove(
                                FindFigureNumber(enPassant.Value + Vector2.UnitX, true).Value);
                        }
                    }
                    else
                        return false;
                    // check for transformation
                    if (to.X == 0)
                    {
                        if (ShowChooseFigureBox != null)
                            ShowChooseFigureBox(this, new EventArgs());
                        pawnToPositionForTransformation = to;
                    }
                }
                #endregion
            }
            else if (movingFigure.Value.Figure == FigureTypes.King)
            {
                #region King rules
                if (Math.Abs(to.X - from.X) > 1)
                    return false;
                else if (Math.Abs(to.Y - from.Y) > 2)
                    return false;
                else if (to.Y - from.Y == 2)
                {
                    if (currentMoveColor == FiguresColor.White)
                    {
                        if (whiteKingsideCastling == false)
                            return false;
                    }
                    else
                    {
                        if (blackKingsideCastling == false)
                            return false;
                    }
                    // all (2) cells free?
                    for (int i = 1; i <= 2; i++)
                        if (FindFigureNumber(from + new Vector2(0, i), true).HasValue)
                            return false;
                    // king go throw unattacked cells?
                    for (int i = 1; i <= 2; i++)
                        if (CanAttackOnCopyBoard(from + new Vector2(0, i)))
                            return false;
                    // move rook (king moves later)
                    if (currentMoveColor == FiguresColor.White)
                    {
                        int rookNumber = FindFigureNumber(new Vector2(0, 7), true).Value;
                        numberFigurePositionColorCopy.Remove(rookNumber);
                        numberFigurePositionColorCopy.Add(rookNumber,
                            new FigurePositionColor(FigureTypes.Rook, new Vector2(0, 5), currentMoveColor));
                    }
                    else
                    {
                        int rookNumber = FindFigureNumber(new Vector2(7, 7), true).Value;
                        numberFigurePositionColorCopy.Remove(rookNumber);
                        numberFigurePositionColorCopy.Add(rookNumber,
                            new FigurePositionColor(FigureTypes.Rook, new Vector2(7, 5), currentMoveColor));
                    }
                }
                else if (to.Y - from.Y == -2)
                {
                    if (currentMoveColor == FiguresColor.White)
                    {
                        if (whiteQueensideCastling == false)
                            return false;
                    }
                    else
                    {
                        if (blackQueensideCastling == false)
                            return false;
                    }
                    // all (3) cells free?
                    for (int i = 1; i <= 3; i++)
                        if (FindFigureNumber(from - new Vector2(0, i), true).HasValue)
                            return false;
                    // king go throw unattacked cells?
                    for (int i = 1; i <= 2; i++)
                        if (CanAttackOnCopyBoard(from - new Vector2(0, i)))
                            return false;
                    // move rook (king moves later)
                    if (currentMoveColor == FiguresColor.White)
                    {
                        int rookNumber = FindFigureNumber(new Vector2(0, 0), true).Value;
                        numberFigurePositionColorCopy.Remove(rookNumber);
                        numberFigurePositionColorCopy.Add(rookNumber,
                            new FigurePositionColor(FigureTypes.Rook, new Vector2(0, 3), currentMoveColor));
                    }
                    else
                    {
                        int rookNumber = FindFigureNumber(new Vector2(7, 0), true).Value;
                        numberFigurePositionColorCopy.Remove(rookNumber);
                        numberFigurePositionColorCopy.Add(rookNumber,
                            new FigurePositionColor(FigureTypes.Rook, new Vector2(7, 3), currentMoveColor));
                    }
                }
                #endregion
            }

            #region Make move on copy board
            // Move figure on test copy of chessboard to check on attacks on King
            // Need to delete figure that positions on 'to' if it exists
            if (attackedFigureNumber.HasValue)
                numberFigurePositionColorCopy.Remove(attackedFigureNumber.Value);

            // Move figure to new position
            FigureTypes figureType = numberFigurePositionColorCopy.
                Values[numberFigurePositionColorCopy.IndexOfKey(figureNumber)].Value.Figure;
            numberFigurePositionColorCopy.Remove(figureNumber);
            numberFigurePositionColorCopy.Add(figureNumber, 
                new FigurePositionColor(figureType, to, currentMoveColor));
            #endregion

            #region Check for king on attacks on copy board
            // Check if king on attack
            if (CanAttackOnCopyBoard(FindFigurePosition(FigureTypes.King, currentMoveColor, true).Value))
                return false;
            #endregion

            #region Save copy board
            // Can make move on "real" chessboard
            numberFigurePositionColor.Clear();
            for (int i = 0; i < numberFigurePositionColorCopy.Count; i++)
                numberFigurePositionColor.Add(numberFigurePositionColorCopy.Keys[i],
                    numberFigurePositionColorCopy.Values[i]);
            #endregion

            // Move performed.

            #region Save en passant postition
            if (movingFigure.Value.Figure == FigureTypes.Pawn &&
                Math.Abs(to.X - from.X) == 2 && to.Y == from.Y)
                enPassant = (to + from) / 2.0f;
            else
                enPassant = null;
            #endregion

            #region Castling limitations
            if (movingFigure.Value.Figure == FigureTypes.King)
            {
                if (currentMoveColor == FiguresColor.White)
                {
                    whiteKingsideCastling = false;
                    whiteQueensideCastling = false;
                }
                else
                {
                    blackKingsideCastling = false;
                    blackQueensideCastling = false;
                }
            }
            else if (movingFigure.Value.Figure == FigureTypes.Rook)
            {
                if (currentMoveColor == FiguresColor.White)
                {
                    if (from.X == 0 && from.Y == 7)
                        whiteKingsideCastling = false;
                    else if (from.X == 0 && from.Y == 0)
                        whiteQueensideCastling = false;
                }
                else
                {
                    if (from.X == 7 && from.Y == 7)
                        blackKingsideCastling = false;
                    else if (from.X == 7 && from.Y == 0)
                        blackQueensideCastling = false;
                }
            }
            #endregion

            #region Change player's move
            if (currentMoveColor == FiguresColor.White)
                currentMoveColor = FiguresColor.Black;
            else
                currentMoveColor = FiguresColor.White;
            #endregion

            return true;
        }

        public void ChangePawnOnBoard(FigureTypes type)
        {
            int? pawnNumber = FindFigureNumber(pawnToPositionForTransformation, false);
            if (!pawnNumber.HasValue)
                return;
            numberFigurePositionColor.Remove(pawnNumber.Value);
            if (pawnToPositionForTransformation.X == 7)
                numberFigurePositionColor.Add(pawnNumber.Value,
                    new FigurePositionColor(type, pawnToPositionForTransformation, FiguresColor.White));
            else
                numberFigurePositionColor.Add(pawnNumber.Value,
                    new FigurePositionColor(type, pawnToPositionForTransformation, FiguresColor.Black));
            if (FigureChanged != null)
                FigureChanged(this, new FigureNumberEventArgs(pawnNumber.Value));
        }

        /// <summary>
        /// Check cell on attacking by another figur.
        /// </summary>
        /// <param name="to">Checking cell position.</param>
        /// <returns>True if attacked, false if not.</returns>
        bool CanAttackOnCopyBoard(Vector2 to)
        {
            if ((to.X < 0) || (to.Y < 0) || (to.X > 7) || (to.Y > 7))
                return false;

            foreach (FigurePositionColor? figure in numberFigurePositionColorCopy.Values)
            {
                // check color
                if (figure.Value.Color == currentMoveColor)
                    continue;
                Vector2 from = figure.Value.Position;
                // Cell not at attack, it occupied by enemy
                if (from == to)
                    return false;
                // check only-attack-rules
                bool next_figure = false;
                if (figure.Value.Figure == FigureTypes.Bishop)
                {
                    if ((to.X - from.X == to.Y - from.Y) && (to.X > from.X)) // right up
                    {
                        for (int i = 0; i < to.X - from.X - 1; i++)
                            if (FindFigureNumber(from + (i + 1) * Vector2.One, true).HasValue)
                                next_figure = true;
                        if (!next_figure)
                            return true;
                    }
                    else if ((to.X - from.X == to.Y - from.Y) && (to.X < from.X)) // left down
                    {
                        for (int i = 0; i < from.X - to.X - 1; i++)
                            if (FindFigureNumber(from - (i + 1) * Vector2.One, true).HasValue)
                                next_figure = true;
                        if (!next_figure)
                            return true;
                    }
                    else if ((to.X - from.X == from.Y - to.Y) && (to.X > from.X)) //right down
                    {
                        for (int i = 0; i < to.X - from.X - 1; i++)
                            if (FindFigureNumber(from + (i + 1) * new Vector2(1.0f, -1.0f), true).HasValue)
                                next_figure = true;
                        if (!next_figure)
                            return true;
                    }
                    else if ((to.X - from.X == from.Y - to.Y) && (to.X < from.X)) //left up
                    {
                        for (int i = 0; i < from.X - to.X - 1; i++)
                            if (FindFigureNumber(from - (i + 1) * new Vector2(1.0f, -1.0f), true).HasValue)
                                next_figure = true;
                        if (!next_figure)
                            return true;
                    }
                }
                else if (figure.Value.Figure == FigureTypes.King)
                {
                    if ((Math.Abs(to.X - from.X) <= 1) && (Math.Abs(to.Y - from.Y) <= 1))
                        return true;
                }
                else if (figure.Value.Figure == FigureTypes.Knight)
                {
                    if (to.X - from.X == 2)
                    {
                        if (Math.Abs(to.Y - from.Y) == 1)
                            return true;
                    }
                    else if (to.X - from.X == 1)
                    {
                        if (Math.Abs(to.Y - from.Y) == 2)
                            return true;
                    }
                    else if (to.X - from.X == -1)
                    {
                        if (Math.Abs(to.Y - from.Y) == 2)
                            return true;
                    }
                    else if (to.X - from.X == -2)
                    {
                        if (Math.Abs(to.Y - from.Y) == 1)
                            return true;
                    }
                }
                else if (figure.Value.Figure == FigureTypes.Pawn)
                {
                    if (figure.Value.Color == FiguresColor.White)
                    {
                        if ((Math.Abs(to.Y - from.Y) == 1) && (to.X - from.X == 1))
                            return true;
                    }
                    else
                    {
                        if ((Math.Abs(to.Y - from.Y) == 1) && (to.X - from.X == -1))
                            return true;
                    }
                }
                else if (figure.Value.Figure == FigureTypes.Queen)
                {
                    if ((to.X - from.X == to.Y - from.Y) && (to.X > from.X)) // right up
                    {
                        for (int i = 0; i < to.X - from.X - 1; i++)
                            if (FindFigureNumber(from + (i + 1) * Vector2.One, true).HasValue)
                                next_figure = true;
                        if (!next_figure)
                            return true;
                    }
                    else if ((to.X - from.X == to.Y - from.Y) && (to.X < from.X)) // left down
                    {
                        for (int i = 0; i < from.X - to.X - 1; i++)
                            if (FindFigureNumber(from - (i + 1) * Vector2.One, true).HasValue)
                                next_figure = true;
                        if (!next_figure)
                            return true;
                    }
                    else if ((to.X - from.X == from.Y - to.Y) && (to.X > from.X)) //right down
                    {
                        for (int i = 0; i < to.X - from.X - 1; i++)
                            if (FindFigureNumber(from + (i + 1) * new Vector2(1.0f, -1.0f), true).HasValue)
                                next_figure = true;
                        if (!next_figure)
                            return true;
                    }
                    else if ((to.X - from.X == from.Y - to.Y) && (to.X < from.X)) //left up
                    {
                        for (int i = 0; i < from.X - to.X - 1; i++)
                            if (FindFigureNumber(from - (i + 1) * new Vector2(1.0f, -1.0f), true).HasValue)
                                next_figure = true;
                        if (!next_figure)
                            return true;
                    }
                    else if ((to.Y == from.Y) && (to.X > from.X)) // right
                    {
                        for (int i = 0; i < to.X - from.X - 1; i++)
                            if (FindFigureNumber(from + (i + 1) * Vector2.UnitX, true).HasValue)
                                next_figure = true;
                        if (!next_figure)
                            return true;
                    }
                    else if ((to.Y == from.Y) && (to.X < from.X)) // left
                    {
                        for (int i = 0; i < from.X - to.X - 1; i++)
                            if (FindFigureNumber(from - (i + 1) * Vector2.UnitX, true).HasValue)
                                next_figure = true;
                        if (!next_figure)
                            return true;
                    }
                    else if ((to.X == from.X) && (to.Y > from.Y)) // up
                    {
                        for (int i = 0; i < to.Y - from.Y - 1; i++)
                            if (FindFigureNumber(from + (i + 1) * Vector2.UnitY, true).HasValue)
                                next_figure = true;
                        if (!next_figure)
                            return true;
                    }
                    else if ((to.X == from.X) && (to.Y < from.Y)) // down
                    {
                        for (int i = 0; i < from.Y - to.Y - 1; i++)
                            if (FindFigureNumber(from - (i + 1) * Vector2.UnitY, true).HasValue)
                                next_figure = true;
                        if (!next_figure)
                            return true;
                    }
                }
                else if (figure.Value.Figure == FigureTypes.Rook)
                {
                    if ((to.Y == from.Y) && (to.X > from.X)) // right
                    {
                        for (int i = 0; i < to.X - from.X - 1; i++)
                            if (FindFigureNumber(from + (i + 1) * Vector2.UnitX, true).HasValue)
                                next_figure = true;
                        if (!next_figure)
                            return true;
                    }
                    else if ((to.Y == from.Y) && (to.X < from.X)) // left
                    {
                        for (int i = 0; i < from.X - to.X - 1; i++)
                            if (FindFigureNumber(from - (i + 1) * Vector2.UnitX, true).HasValue)
                                next_figure = true;
                        if (!next_figure)
                            return true;
                    }
                    else if ((to.X == from.X) && (to.Y > from.Y)) // up
                    {
                        for (int i = 0; i < to.Y - from.Y - 1; i++)
                            if (FindFigureNumber(from + (i + 1) * Vector2.UnitY, true).HasValue)
                                next_figure = true;
                        if (!next_figure)
                            return true;
                    }
                    else if ((to.X == from.X) && (to.Y < from.Y)) // down
                    {
                        for (int i = 0; i < from.Y - to.Y - 1; i++)
                            if (FindFigureNumber(from - (i + 1) * Vector2.UnitY, true).HasValue)
                                next_figure = true;
                        if (!next_figure)
                            return true;
                    }
                }
            }

            return false;
        }

        #endregion

        #region Helper functions

        /// <summary>
        /// Find figure's type by it number.
        /// </summary>
        /// <param name="figureNumber">Number of figure.</param>
        /// <returns>Figure's type.</returns>
        public FigureTypes? FigureType(int figureNumber)
        {
            FigurePositionColor? fpc;
            if (numberFigurePositionColor.TryGetValue(figureNumber, out fpc))
                return fpc.Value.Figure;
            else
                return null;
        }

        /// <summary>
        /// Find figure's position by it number.
        /// </summary>
        /// <param name="figureNumber">Number of figure.</param>
        /// <returns>Position on chessboard.</returns>
        public Vector2? FigurePosition(int figureNumber)
        {
            FigurePositionColor? fpc;
            if (numberFigurePositionColor.TryGetValue(figureNumber, out fpc))
                return fpc.Value.Position;
            else
                return null;
        }

        /// <summary>
        /// Find figure's color by it number.
        /// </summary>
        /// <param name="figureNumber">Number of figure.</param>
        /// <returns>Figure's color.</returns>
        public FiguresColor? FigureColor(int figureNumber)
        {
            FigurePositionColor? fpc;
            if (numberFigurePositionColor.TryGetValue(figureNumber, out fpc))
                return fpc.Value.Color;
            else
                return null;
        }

        /// <summary>
        /// Check if figure exists at this moment.
        /// </summary>
        /// <param name="figureNumber">Number of figure.</param>
        /// <returns>True, if exists, and false - otherwise.</returns>
        public bool CheckFigureExistence(int figureNumber)
        {
            return numberFigurePositionColor.ContainsKey(figureNumber);
        }

        /// <summary>
        /// Find figure.
        /// </summary>
        /// <param name="position">Figure position.</param>
        /// <param name="findOnCopy">If true - search on board temporary copy.</param>
        /// <returns>Figure number or null.</returns>
        int? FindFigureNumber(Vector2 position, bool findOnCopy)
        {
            FigurePositionColor? fpc;
            if (!findOnCopy)
            {
                for (int i = 0; i < figuresNumber; i++)
                    if (numberFigurePositionColor.TryGetValue(i, out fpc))
                        if (fpc.Value.Position == position)
                            return i;
            }
            else
            {
                for (int i = 0; i < figuresNumber; i++)
                    if (numberFigurePositionColorCopy.TryGetValue(i, out fpc))
                        if (fpc.Value.Position == position)
                            return i;
            }
            return null;
        }

        Vector2? FindFigurePosition(FigureTypes type, FiguresColor color, bool findOnCopy)
        {
            FigurePositionColor? fpc;
            if (!findOnCopy)
            {
                for (int i = 0; i < figuresNumber; i++)
                    if (numberFigurePositionColor.TryGetValue(i, out fpc))
                        if ((fpc.Value.Color == color) && (fpc.Value.Figure == type))
                            return fpc.Value.Position;
            }
            else
            {
                for (int i = 0; i < figuresNumber; i++)
                    if (numberFigurePositionColorCopy.TryGetValue(i, out fpc))
                        if ((fpc.Value.Color == color) && (fpc.Value.Figure == type))
                            return fpc.Value.Position;
            }
            return null;
        }

        #endregion
    }
}